package tool

import (
	"github.com/golang-jwt/jwt/v4"
	"go-gin-init/app/core"
	"go-gin-init/app/models/resp"
	"go-gin-init/common/xerr"
	"time"
)

type JWT struct {
	SigningKey []byte
}

func NewJWT() *JWT {
	return &JWT{
		[]byte(core.Conf.Server.SigningKey),
	}
}

// CreateToken 创建一个token
func (j *JWT) CreateToken(claims resp.CustomClaims) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(j.SigningKey)
}

func (j *JWT) CreateClaims(baseClaims resp.BaseClaims) resp.CustomClaims {
	expireTime := core.Conf.JWTAuth.AccessExpire
	claims := resp.CustomClaims{
		BaseClaims: baseClaims,
		RegisteredClaims: jwt.RegisteredClaims{
			Audience:  jwt.ClaimStrings{"gin-init"},                                              // 受众
			NotBefore: jwt.NewNumericDate(time.Now().Add(-1000)),                                 // 签名生效时间
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expireTime) * time.Hour)), // 过期时间 1天  配置文件
			Issuer:    core.Conf.JWTAuth.Issuer,                                                  // 签名的发行者
		},
	}
	return claims
}

// ParseToken 解析 token
func (j *JWT) ParseToken(tokenString string) (*resp.CustomClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &resp.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) {
		return j.SigningKey, nil
	})

	if token == nil {
		return nil, xerr.NewErrCode(xerr.TOKEN_INVALID)
	}

	claims, ok := token.Claims.(*resp.CustomClaims)
	if !ok || !token.Valid {
		return nil, xerr.NewErrCode(xerr.TOKEN_INVALID)
	}

	if err != nil {
		if ve, ok := err.(*jwt.ValidationError); ok {
			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
				return nil, xerr.NewErrCode(xerr.TOKEN_MALFORMED)
			} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
				// Token is expired,should return claims
				return claims, xerr.NewErrCode(xerr.TOKEN_EXPIRED)
			} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
				return nil, xerr.NewErrCode(xerr.TOKEN_NOT_VALID_YET)
			} else {
				return nil, xerr.NewErrCode(xerr.TOKEN_INVALID)
			}
		}
	}

	return claims, nil
	//if token != nil {
	//	if claims, ok := token.Claims.(*resp.CustomClaims); ok && token.Valid {
	//		return claims, nil
	//	}
	//	return nil, xerr.NewErrCode(xerr.TOKEN_INVALID)
	//
	//} else {
	//	return nil, xerr.NewErrCode(xerr.TOKEN_INVALID)
	//}
}
